from pod.std import *
#from pod.macros.html.util import tag, css
import cairo
import math
from shape import *

class ContextHolder(object):
    def __init__(self, ctx):
        self.dctx = self.getCurrentContext(ctx.scope)

    @staticmethod
    def getCurrentContext(scope):
        for s in scope[::-1]:
            if isinstance(s, Canvas) or isinstance(s, ContextHolder):
                return s.dctx
                
        print "Error: No context found!"
                        
    def getPositionalArgs(self, args):
        result = []
        pos = 0
        while pos < len(args):
            if isinstance(args[pos], Point):
                result.append(args[pos])
                pos += 1
            else:
                result.append(Point(args[pos], args[pos+1]))
                pos += 2
            #endif

        return (result, pos)

class Canvas(Macro):
    name = "canvas"
    doctype = "html"

    def __init__(self, ctx, width=None, height=None, filename=None):
        super(Canvas, self).__init__()
        self.filename = filename

        if self.filename != None and width != None and height != None:
            self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
            self.dctx = cairo.Context(self.surface)
        else:
            parent = ctx.scope[-1]
            self.dctx = parent.dctx


    def __call__(self, content):
        if self.filename:
            self.surface.write_to_png(self.filename)
            return "<img src='%s'>" % self.filename

class SourceRGBA(Macro):
    name = "rgba"
    doctype="html"
    
    def __init__(self, ctx, r, g, b, a):
        super(SourceRGBA, self).__init__()
        self.color = (r, g, b, a)
        
    def __call__(self, content):
        return RGBAColor(self.color)

class Clip(Macro):
    name = "clip"
    doctype = "html"
    
    def __init__(self, ctx):
        self.dctx = ctx.scope[-1].dctx
        
    def __call__(self, content):
        for item in content:
            if isinstance(item, Drawable):
                item.draw(self.dctx)
                
        self.dctx.clip()
        
class Stroke(ContextHolder, Macro):
    name = "stroke"
    doctype = "html"
    
    def __init__(self, ctx, color=None, linewidth=None):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
        self.ctx = ctx
        
        if color: self.color = color
        else: self.color = RGBAColor(0, 0, 0, 1)
        
        if linewidth: self.linewidth=linewidth
        else: self.linewidth = 1        
        
    def __call__(self, content):
        for item in content:
            if isinstance(item, Drawable):
                item.draw(self.dctx)
                
        self.dctx.set_source_rgba(*self.color.rgba)
        self.dctx.set_line_width(max(self.dctx.device_to_user_distance(self.linewidth, self.linewidth)))
        self.dctx.stroke()
        
class Fill(ContextHolder, Macro):
    name = "fill"
    doctype = "html"
    
    def __init__(self, ctx, color=None, preserve=False, rule=None):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
        self.color = color
        self.preserve = preserve
        self.rule = cairo.FILL_RULE_EVEN_ODD if rule == "even_odd" else cairo.FILL_RULE_WINDING
        
    def __call__(self, content):
        for item in content:
            if isinstance(item, Drawable):
                item.draw(self.dctx)
                
        self.dctx.set_source_rgba(*self.color.rgba)
        self.dctx.set_fill_rule(self.rule)
        if not self.preserve: self.dctx.fill()
        else: self.dctx.fill_preserve()

class PointPrimitive(Macro):
    name = "point"
    doctype = "html"

    def __init__(self, ctx, x, y):
        super(PointPrimitive, self).__init__()
        self.point = Point(x, y)

    def __call__(self, content):
        return self.point
        
class MakeNode(Macro):
    name = "makeNode"
    doctype = "html"
    
    def __init__(self, ctx, name, x, y):
        ctx.setGlobalVar("drawing.node.%s" % name, Point(x, y))
        
class Node(Macro):
    name = "node"
    doctype = "html"
    
    def __init__(self, ctx, name):
        self.point = ctx.getGlobalVar("drawing.node.%s" % name)
        
    def __call__(self, content):
        return self.point
        
class MakePoint(Macro):
    name = "point"
    doctype = "html"
    
    def __init__(self, ctx, x, y):
        self.point = Point(x, y)
        
    def __call__(self, content):
        return self.point
        
class Line(ContextHolder, Macro):
    name = "line"
    doctype = "html"
    
    def __init__(self, ctx, *args):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
        points, last = self.getPositionalArgs(args)
        self.shape = LineShape(points)
        
    def __call__(self, content):
        return self.shape
        
class LineTo(ContextHolder, Macro):
    name = "lineTo"
    doctype = "html"
    
    def __init__(self, ctx, *args):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)        
        points, last = self.getPositionalArgs(args)
        self.shape = LineToShape(points[0])
        
    def __call__(self, content):
        return self.shape

class Lines(ContextHolder, Macro):
    name = "lines"
    doctype = "html"
    
    def __init__(self, ctx):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
        
    def __call__(self, content):
        return LineCollectionShape(content)

class Rectangle(ContextHolder, Macro):
    name = "rectangle"
    doctype = "html"

    def __init__(self, ctx, x, y, w, h):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
        self.shape = RectangleShape(x, y, w, h)

    def __call__(self, content):
        return self.shape
        
class Circle(ContextHolder, Macro):
    name = "circle"
    doctype = "html"
    
    def __init__(self, ctx, *args, **kwargs): #radius=10, reverse=False):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
        points, last = self.getPositionalArgs(args)
        self.shape = CircleShape(points, kwargs.get("radius", 10), kwargs.get("reverse", False))
    
    def __call__(self, content):
        return self.shape

class Translate(ContextHolder, Macro):
    name = "translate"
    doctype = "html"
    
    def __init__(self, ctx, x, y):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
        self.dctx.save()
        self.dctx.translate(x, y)
        
    def __call__(self, content):
        self.dctx.restore()

class Scale(ContextHolder, Macro):
    name = "scale"
    doctype = "html"
    
    def __init__(self, ctx, xscale=1, yscale=1):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
        self.dctx.save()
        self.dctx.scale(xscale, yscale)
        
    def __call__(self, content):
        self.dctx.restore()
        
class Rotate(ContextHolder, Macro):
    name = "rotate"
    doctype = "html"
    
    def __init__(self, ctx, angle):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
        self.dctx.save()
        self.dctx.rotate(angle)
        
    def __call__(self, content):
        self.dctx.restore()

class SubPath(ContextHolder, Macro):
    name = "subpath"
    doctype = "html"
    
    def __init__(self, ctx):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
        
    def __call__(self, content):
        return SubPathCommand()
        
class ClosePath(ContextHolder, Macro):
    name = "closePath"
    doctype = "html"
    
    def __init__(self, ctx):
        Macro.__init__(self)
        ContextHolder.__init__(self, ctx)
                
    def __call__(self, content):
        return ClosePathCommand()

class MathText(Macro):
    name = "mathtext"
    doctype = "html"
    
    def __init__(self, ctx, x, y):
        super(MathText, self).__init__()
        self.point = Point(x, y)
        
    def __call__(self, content):
        return MathTextShape(self.point, "".join(Macro.flatten(content)))

class Text(Macro):
    name = "text"
    doctype = "html"
    
    def __init__(self, ctx, x, y, size=12, font="Georgia", slant="normal", bold=False):
        super(Text, self).__init__()
        self.point = Point(x, y)
        self.size = size
        self.font = font
        self.slant = slant
        self.bold = bold
        
    def __call__(self, content):
        return TextShape(self.point, "".join(Macro.flatten(content)), self.size, self.font, self.slant, self.bold)